package org.goodsl.mdd

import java.lang.annotation.Annotation
import org.goodsl.mdd.annotation.ValueType
import org.goodsl.mdd.annotation.Setting
import java.lang.reflect.Field

import org.goodsl.mdd.validator.AllowNullValidator

/**
 * Created with IntelliJ IDEA.
 * User: Simon Xiao
 * Date: 12-11-13
 * Time: 上午9:55
 * To change this template use File | Settings | File Templates.
 */
class SegInfo {

    private final static String VALIDATOR_FIELD = "validator"
    Class<? extends Seg> type

    private void setType(Class<? extends Seg> type) {
        this.type = type
    }

    Class valueType

    private void setValueType(Class valueType) {
        this.valueType = valueType
    }

    Class typeConvertor

    protected TypeSetting setting
    public TypeSetting getSetting(){
        return setting
    }

    private void setTypeConvertor(Class convertor) {
        this.typeConvertor = convertor
    }

    /**
     * 校验器
     */
    private ArrayList<Validator<Seg>> validators
    private ArrayList<Validator<Seg>> getValidators(){
        return validators
    }
    private void setValidators(ArrayList<Validator<Seg>> vs){
        validators = vs
    }


	@SuppressWarnings("rawtypes")
	private SegInfo(Class<? extends Seg> cz, Class valueType, Validator[] vs) {
        this.type = cz
        this.valueType = valueType
        if (this.valueType.isPrimitive()) {
            this.valueType = getAutoBoxedType(this.valueType)
        }
        if (vs != null && vs.length > 0) {
            if (validators == null)
                validators = new ArrayList<Validator>(vs.length)
            vs.each {
                validators.add(it)
            }
        }

    }

    public ValidResult verify(Seg seg) {
        ValidResult result = new ValidResult()
        if (validators != null && validators.size() > 0) {
            for (Validator it in validators) {
                SingleValidResult<Seg> singleResult = it.verify(seg)
                if (singleResult == null) continue;

                if (it instanceof AllowNullValidator) {
                    if (singleResult.isValid) { //值为空，其他校验不用做了
                        result.clear();
                        result.addSingleResult(singleResult);
                        return result;
                    }

                }else
                    result.addSingleResult(singleResult)


            }
        }

        return result
    }

    //************************* 以下为静态处理**************************

    private static HashMap<Class, SegInfo> segInfos = new HashMap<Class, SegInfo>()

    public static SegInfo getSegInfo(Class<?> cz) {
        if (segInfos.containsKey(cz))
            return segInfos[cz]

        SegInfo segInfo = parseSegInfo(cz)
        if (segInfo != null)
            segInfos.put(cz, segInfo)
        return segInfo

    }

    private static SegInfo parseSegInfo(Class<?> cz) {
        Validator[] validators = null
        Annotation at = cz.getAnnotation(ValueType)
        if (at == null)
            return null

        Class valueType = at.value()
        if (!Seg.isAssignableFrom(cz))
            throw new ParseException("${cz.name} 必须继承自 ${Seg.name}")
        if (valueType == null) {
            throw new ParseException("类型${cz.name} 需要在ValueType 标注中指定值类型")
        }

        Field validField = null
        try {
            validField = cz.getDeclaredField(VALIDATOR_FIELD)
        }
        catch (NoSuchFieldException e) {}

        if (validField != null) {
            Object o = cz.newInstance()
            Object validObject = o."$VALIDATOR_FIELD"

            if (validObject != null) {
                if (!(validObject instanceof Closure)) {
                    throw new ParseException("类型${cz.name} 的校验器定义必须为闭包")
                }
                Closure validMaker = (Closure) validObject
                ClosureValidatorDelegate<Seg> delegate = new ClosureValidatorDelegate<Seg>()
                validMaker.delegate = delegate
                validMaker.resolveStrategy = Closure.DELEGATE_FIRST
                validators = validMaker()
            }
        }

        SegInfo segInfo = new SegInfo((Class<? extends Seg>) cz, valueType, validators)
        segInfo.typeConvertor = at.typeConvertor()

        segInfo.setting = new TypeSetting()
        Annotation note = cz.getAnnotation(Setting)
        if (note!=null){
            segInfo.setting.reset(note)
        }

        return segInfo
    }

    private static Hashtable<Class, Class> primitives =
        new Hashtable<Class, Class>(8)
    static {
        primitives[int] = Integer
        primitives[boolean] = Boolean
        primitives[long] = Long
        primitives[short] = Short
        primitives[float] = Float
        primitives[char] = Character
        primitives[double] = Double
        primitives[byte] = Byte

    }

    public static Class getAutoBoxedType(Class cz) {
        return primitives[cz]
    }
}


